# -*- coding: utf-8 -*-
import abc
import base64
import json

from Crypto.Cipher import AES
import requests

from common.log import logger
import settings as miniweixin_settings


class API(object):
    __metaclass__ = abc.ABCMeta
    timeout = 10
    ssl_verify = False

    def http_get(self, _http_url, **kwargs):
        """
        http 请求GET方法
        """
        try:
            resp = requests.get(_http_url, params=kwargs, timeout=self.timeout, verify=self.ssl_verify)
            resp = resp.json()
            return resp
        except Exception as error:
            logger.error('requests get url:%s error: %s' % (_http_url, error))
            return {}

    def http_post(self, _http_url, **kwargs):
        """
        http 请求POST方法
        """
        try:
            resp = requests.post(_http_url, json=kwargs, timeout=self.timeout, verify=self.ssl_verify)
            resp = resp.json()
            return resp
        except Exception as error:
            logger.error('requests post url:%s kwargs: %s error %s' % (_http_url, kwargs, error))
            return {}


class WXBizDataCrypt:
    def __init__(self, app_id, session_key):
        self.app_id = app_id
        self.session_key = session_key

    def decrypt(self, encrypted_data, iv):
        # base64 decode
        session_key = base64.b64decode(self.session_key)
        encrypted_data = base64.b64decode(encrypted_data)
        iv = base64.b64decode(iv)

        cipher = AES.new(session_key, AES.MODE_CBC, iv)

        decrypted = json.loads(self._unpad(cipher.decrypt(encrypted_data)))

        if decrypted['watermark']['appid'] != self.app_id:
            raise Exception('Invalid Buffer')

        return decrypted

    def _unpad(self, s):
        return s[:-ord(s[len(s) - 1:])]


class MiniWeiXinApi(API):
    # 登录票据CODE验证URL
    WEIXIN_CHECK_CODE_URL = 'https://api.weixin.qq.com/sns/jscode2session'

    def __init__(self):
        super(MiniWeiXinApi, self).__init__()
        self.app_id = miniweixin_settings.MINIWEIXIN_APP_ID
        self.secret = miniweixin_settings.MINIWEIXIN_APP_SECRET

    def http_get(self, _http_url, **kwargs):
        data = super(MiniWeiXinApi, self).http_get(_http_url, **kwargs)
        if 'errcode' in data:
            logger.error('mini weixin api (url: %s) return error: %s' % (_http_url, data))
            return {}
        return data

    def http_post(self, _http_url, **kwargs):
        data = super(MiniWeiXinApi, self).http_post(_http_url, **kwargs)
        if 'errcode' in data:
            logger.error('mini weixin api (url: %s) return error: %s' % (_http_url, data))
            return {}
        return data

    def check_login_code(self, code):
        """
        校验登录回调code
        """
        query_param = {
            'appid': self.app_id,
            'secret': self.secret,
            "js_code": code,
            "grant_type": "authorization_code"
        }
        data = self.http_get(self.WEIXIN_CHECK_CODE_URL, **query_param)
        session_key = data.get('session_key')
        openid = data.get('openid')
        if session_key is None or openid is None:
            logger.error(u"小程序登录票据CODE接口返回无session_key或openid")
            return False, {}
        return True, {'session_key': session_key, 'openid': openid}

    def get_user_info(self, session_key, encrypted_data, iv):
        """
        获取用户授权的用户信息
        """
        # 解密数据
        pc = WXBizDataCrypt(self.app_id, session_key)
        try:
            userinfo = pc.decrypt(encrypted_data, iv)
        except Exception as error:
            logger.error(error)
            return None
        if not userinfo.get('openId'):
            logger.error(u"小程序解密用户信息无openid, 解密数据为%s" % userinfo)
            return None
        return {
            'openid': userinfo.get('openId'),
            'nickname': userinfo.get('nickName') or '',
            'gender': userinfo.get('gender') or '',
            'city': userinfo.get('city') or '',
            'province': userinfo.get('province') or '',
            'country': userinfo.get('country') or '',
            'avatar_url': userinfo.get('avatarUrl') or ''
        }
